/* See LICENSE for copyright and terms of use */

/**
 * <p>A non-sequential array.</p>
 *
 * <p>Iterate over the instance itself to access the items.</p>
 *
 * @author Tay Ray Chuan
 */

class org.evtmng.util.List {
	/**
	 * <p>The number of items in this instance.</p>
	 */
	private var m_len:Number;

	public function List() {
		init();
	}

	private function init():Void {
		m_len = 0;
		_global.ASSetPropFlags(this, ["m_len"], 1);
	}

	//******************************************************
  //*           Adding/Removing Items
  //******************************************************

	/**
	 * @throws Error if an object with <code>id</code> is already inserted.
	 */
	public function addItemWithId(item:Object, id:Number):Void {
		if(this[id]!=null) {
			throw new Error("item already added!");
		}
		this[id] = item;
		m_len++;
	}

	/**
	 * @throws Error if an object with <code>id</code> has yet to be inserted.
	 */
	public function removeItemWithId(id:Number):Void {
		if(this[id]==null) {
			throw new Error("no such item!");
		}
		delete this[id];
		m_len--;
	}

	public function removeItem(item:Object):Void {
		for(var i:String in this) {
			if(this[i] == item) {
				delete this[i];
				m_len--;
			}
		}
	}

	public function removeAllItems():Void {
		for(var i:String in this) {
			this[i] = null;
			delete this[i];
		}
		init();
	}

	//******************************************************
  //*           Accessing Items
  //******************************************************

  public function itemForId(id:Number):Object {
  	return this[id];
  }

  public function idForItem(item:Object):Number {
  	for(var i:String in this) {
  		if(this[i] == item) {
  			return parseInt(i);
  		}
  	}
  }

  public function allIdsForItem(item:Object):Array {
  	var ret:Array = [];
  	for(var i:String in this) {
  		if(this[i] == item) {
  			ret.push(parseInt(i));
  		}
  	}
  	return ret;
  }

	//******************************************************
  //*           Sorting Items
  //******************************************************

	/**
	 * @param compare <p>Method with signature<br/>
	 * <code>function(val1:Object, val2:Object):Boolean</code>
	 * </p>
	 *
	 * <p>
	 * Iterates through the items in this instance and passes them to <code>compare</code>. A
	 * sequence of the items is generated after the iteration, and all items are then destroyed and
	 * added in this sequence.
	 * </p>
	 *
	 * <p>
	 * For ascending and descending sorts see {@link org.evtmng.test.unit.ListTest#testAscendingListSort}
	 * and {@link org.evtmng.test.unit.ListTest#testDescendingListSort}
	 * </p>
	 *
	 * @see org.evtmng.test.unit.ListTest
	 */
  public function sortUsingFunction(compare:Function):Void {
		var keys:Array = [];
		var vals:Array = [];

		for(var i:String in this) {
			keys.push(i);
			vals.push(this[i]);
		}

  	var tmp:Object;
  	for(var i:Number = 0;i<keys.length;i++) {
  		for(var j:Number = 0;j<keys.length;j++) {
  			if(compare(vals[i], vals[j])==true) {
  				tmp = keys[i];
  				keys[i] = keys[j];
  				keys[j] = tmp;

  				tmp = vals[i];
  				vals[i] = vals[j];
  				vals[j] = tmp;
  			}
  		}
  	}

		for(var i:String in this) {
			this[i] = null;
			delete this[i];
		}

  	for(var i:String in keys) {
  		this[keys[i]] = vals[i];
  	}
	}

	//******************************************************
  //*           Accessing Attributes
  //******************************************************

  public function length():Number {
  	return m_len;
  }
}
